// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

/*
 * This file may have been modified by Bytedance Ltd. and/or its affiliates (“ Bytedance's Modifications”).
 * All Bytedance's Modifications are Copyright (2023) Bytedance Ltd. and/or its affiliates.
 */

#pragma once

#include <string>
#include <Common/Slice.h>

namespace DB::IndexFile
{
class Status
{
public:
    // Create a success status.
    Status() : state_(nullptr) { }
    ~Status() { delete[] state_; }

    // Copy the specified status.
    Status(const Status & s);
    void operator=(const Status & s);

    // Return a success status.
    static Status OK() { return Status(); }

    // Return error status of an appropriate type.
    static Status NotFound(const Slice & msg, const Slice & msg2 = Slice()) { return Status(kNotFound, msg, msg2); }
    static Status Corruption(const Slice & msg, const Slice & msg2 = Slice()) { return Status(kCorruption, msg, msg2); }
    static Status NotSupported(const Slice & msg, const Slice & msg2 = Slice()) { return Status(kNotSupported, msg, msg2); }
    static Status InvalidArgument(const Slice & msg, const Slice & msg2 = Slice()) { return Status(kInvalidArgument, msg, msg2); }
    static Status IOError(const Slice & msg, const Slice & msg2 = Slice()) { return Status(kIOError, msg, msg2); }

    // Returns true iff the status indicates success.
    bool ok() const { return (state_ == nullptr); }

    // Returns true iff the status indicates a NotFound error.
    bool IsNotFound() const { return code() == kNotFound; }

    // Returns true iff the status indicates a Corruption error.
    bool IsCorruption() const { return code() == kCorruption; }

    // Returns true iff the status indicates an IOError.
    bool IsIOError() const { return code() == kIOError; }

    // Returns true iff the status indicates a NotSupportedError.
    bool IsNotSupportedError() const { return code() == kNotSupported; }

    // Returns true iff the status indicates an InvalidArgument.
    bool IsInvalidArgument() const { return code() == kInvalidArgument; }

    // Return a string representation of this status suitable for printing.
    // Returns the string "OK" for success.
    std::string ToString() const;

private:
    // OK status has a null state_.  Otherwise, state_ is a new[] array
    // of the following form:
    //    state_[0..3] == length of message
    //    state_[4]    == code
    //    state_[5..]  == message
    const char * state_;

    enum Code
    {
        kOk = 0,
        kNotFound = 1,
        kCorruption = 2,
        kNotSupported = 3,
        kInvalidArgument = 4,
        kIOError = 5
    };

    Code code() const { return (state_ == nullptr) ? kOk : static_cast<Code>(state_[4]); }

    Status(Code code, const Slice & msg, const Slice & msg2);
    static const char * CopyState(const char * s);
};

inline Status::Status(const Status & s)
{
    state_ = (s.state_ == nullptr) ? nullptr : CopyState(s.state_);
}
inline void Status::operator=(const Status & s)
{
    // The following condition catches both aliasing (when this == &s),
    // and the common case where both s and *this are ok.
    if (state_ != s.state_)
    {
        const char * tmp = state_;
        state_ = (s.state_ == nullptr) ? nullptr : CopyState(s.state_);
        delete[] tmp;
    }
}

}
